﻿#region License
// MIT License
//
// Copyright(c) 2019-2025 ZhangYu
// https://gitee.com/zhangyu800/litebyte
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#region Intro
// Purpose: Convert base type to bytes
// Author: ZhangYu
// CreateDate: 2025-02-13
// LastModifiedDate: 2025-08-26
#endregion
namespace LiteByte.Converters {

    using System.Text;
    using LiteByte.Common;

    /// <summary> 基本类型写入器 | Base type writer </summary>
    public class BaseTypeWriter : NumberWriter {

        #region 字段 | Fields
        /// <summary> Java时间戳(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks) </summary>
        protected const long EpochTicks = 621355968000000000;
        // 字符串编码器
        protected static Encoding ASCII = Encoding.ASCII;
        protected static Encoding UTF8 = Encoding.UTF8;
        protected static Encoding UTF16 = Encoding.Unicode;
        protected static Encoding UTF32 = Encoding.UTF32;
        private static Encoding _gbk = null;
        protected static Encoding GBK {
            get {
                if (_gbk == null) {
                    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                    _gbk = Encoding.GetEncoding("GBK");
                }
                return _gbk;
            }
        }
        #endregion

        #region 构造方法 | Constructors
        public BaseTypeWriter() : base() { }
        public BaseTypeWriter(int capacity) : base(capacity) { }
        #endregion

        #region 十进制小数 | Decimal
        public void WriteDecimal(decimal value) {
            bool isNegative = value < 0 ? true : false;
            string str = isNegative ? (-value).ToString() : value.ToString();
            // 写入正负符号
            WriteBit1(isNegative);
            // 写入字符串长度
            WriteVUInt32((uint)str.Length);
            // 写入0-9或.
            EnsureCapacity((int)Math.Ceiling(0.5f * str.Length));
            for (int i = 0; i < str.Length; i++) {
                char c = str[i];
                if (c >= '0' && c <= '9') {
                    WriteBits(4, (byte)(c - 48));
                } else if (c == '.') {
                    WriteBits(4, 10);
                }
            }
        }
        #endregion

        #region 日期时间 | DateTime
        public void WriteDateTime(DateTime value) {
            // C# Ticks 转换为Java毫秒时间戳(Java时间戳：自UTC 1970年1月1日午夜以来的毫秒数. 1 Tick = 10000毫秒）
            long timestamp = (value.Ticks - EpochTicks) / 10000;
            WriteVInt64(timestamp);
        }
        #endregion

        #region 字符串 | String
        /// <summary> 写入变长Unicode字符串 | Write variable-length unicode string </summary>
        public void WriteVUnicode(string value) {
            // 检查参数
            if (value == null) {
                WriteBit1(true);
                return;
            }
            if (value.Length == 0) {
                WriteBit1(false);
                WriteVUInt32(0);
                return;
            }
            WriteBit1(false);

            // 计算字符数
            int charCount = 0;
            for (int i = 0; i < value.Length;) {
                charCount += 1;
                i += char.IsHighSurrogate(value[i]) ? 2 : 1;
            }

            // 写入字符数
            WriteVUInt32((uint)charCount);

            // 写入Unicode码点
            EnsureCapacity(charCount * 4);
            for (int i = 0; i < value.Length;) {
                uint codePoint = 0;
                if (char.IsHighSurrogate(value[i])) {
                    codePoint = (uint)char.ConvertToUtf32(value[i++], value[i++]);
                } else {
                    codePoint = value[i++];
                }
                WriteVUInt32(codePoint);
            }
        }

        /// <summary> 写入ASCII编码字符串 | Write ASCII string </summary>
        public void WriteASCII(string value) {
            WriteString(value, ASCII);
        }

        /// <summary> 写入UTF-8编码字符串 | Write UTF-8 string </summary>
        public void WriteUTF8(string value) {
            WriteString(value, UTF8);
        }

        /// <summary> 写入UTF-16编码字符串 | Write UTF-16 string </summary>
        public void WriteUTF16(string value) {
            WriteString(value, UTF16);
        }

        /// <summary> 写入UTF-32编码字符串 | Write UTF-32 string </summary>
        public void WriteUTF32(string value) {
            WriteString(value, UTF32);
        }

        /// <summary> 写入GBK编码字符串 | Write GBK string </summary>
        public void WriteGBK(string value) {
            WriteString(value, GBK);
        }

        protected void WriteString(string value, Encoding encoding) {
            // 检查参数
            if (value == null) {
                WriteBit1(true);
                return;
            }
            if (value.Length == 0) {
                WriteBit1(false);
                WriteVUInt32(0);
                return;
            }
            WriteBit1(false);
            // 写入字节数
            int byteCount = encoding.GetByteCount(value);
            WriteVUInt32((uint)byteCount);
            EnsureCapacity(byteCount);
            // 写入字符串数据
            byteIndex += encoding.GetBytes(value, 0, value.Length, buffer, byteIndex);
        }
        #endregion

        #region 基本类型 | BaseType
        /// <summary> 写入基本类型数据 | Write base type data </summary>
        public void WriteBaseType(TypeName baseType, object value) {
            switch (baseType) {
                case TypeName.Bit1: WriteBit1((bool)value); break;
                case TypeName.Bit2: WriteBit2((byte)value); break;
                case TypeName.Bit3: WriteBit3((byte)value); break;
                case TypeName.Bit4: WriteBit4((byte)value); break;
                case TypeName.Bit5: WriteBit5((byte)value); break;
                case TypeName.Bit6: WriteBit6((byte)value); break;
                case TypeName.Bit7: WriteBit7((byte)value); break;
                case TypeName.Bit8: WriteBit8((byte)value); break;
                case TypeName.Bool: WriteBool((bool)value); break;
                case TypeName.Char: WriteChar((char)value); break;
                case TypeName.UInt8: WriteUInt8((byte)value); break;
                case TypeName.UInt16: WriteUInt16((ushort)value); break;
                case TypeName.UInt32: WriteUInt32((uint)value); break;
                case TypeName.UInt64: WriteUInt64((ulong)value); break;
                case TypeName.Int8: WriteInt8((sbyte)value); break;
                case TypeName.Int16: WriteInt16((short)value); break;
                case TypeName.Int32: WriteInt32((int)value); break;
                case TypeName.Int64: WriteInt64((long)value); break;
                case TypeName.Float16: WriteFloat16((Half)value); break;
                case TypeName.Float32: WriteFloat32((float)value); break;
                case TypeName.Float64: WriteFloat64((double)value); break;
                case TypeName.VUInt16: WriteVUInt16((ushort)value); break;
                case TypeName.VUInt32: WriteVUInt32((uint)value); break;
                case TypeName.VUInt64: WriteVUInt64((ulong)value); break;
                case TypeName.VInt16: WriteVInt16((short)value); break;
                case TypeName.VInt32: WriteVInt32((int)value); break;
                case TypeName.VInt64: WriteVInt64((long)value); break;
                case TypeName.Decimal: WriteDecimal((decimal)value); break;
                case TypeName.DateTime: WriteDateTime((DateTime)value); break;
                case TypeName.VUnicode: WriteVUnicode((string)value); break;
                case TypeName.ASCII: WriteASCII((string)value); break;
                case TypeName.UTF8: WriteUTF8((string)value); break;
                case TypeName.UTF16: WriteUTF16((string)value); break;
                case TypeName.UTF32: WriteUTF32((string)value); break;
                case TypeName.GBK: WriteGBK((string)value); break;
                default: throw new Exception($"Unknown base type: {baseType}");
            }
        }
        #endregion

    }

}
